home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Human Interface Toolbox / CarbonCustomList / CarbonCustomList.c next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  18.7 KB  |  677 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        CarbonCustomList.c
  3.     
  4.     Description:A simple application that implements a custom list under Carbon.
  5.  
  6.     Author:        SC
  7.  
  8.     Copyright:     © Copyright 2000 Apple Computer, Inc. All rights reserved.
  9.     
  10.     Disclaimer:    IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  11.                 ("Apple") in consideration of your agreement to the following terms, and your
  12.                 use, installation, modification or redistribution of this Apple software
  13.                 constitutes acceptance of these terms.  If you do not agree with these terms,
  14.                 please do not use, install, modify or redistribute this Apple software.
  15.  
  16.                 In consideration of your agreement to abide by the following terms, and subject
  17.                 to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
  18.                 copyrights in this original Apple software (the "Apple Software"), to use,
  19.                 reproduce, modify and redistribute the Apple Software, with or without
  20.                 modifications, in source and/or binary forms; provided that if you redistribute
  21.                 the Apple Software in its entirety and without modifications, you must retain
  22.                 this notice and the following text and disclaimers in all such redistributions of
  23.                 the Apple Software.  Neither the name, trademarks, service marks or logos of
  24.                 Apple Computer, Inc. may be used to endorse or promote products derived from the
  25.                 Apple Software without specific prior written permission from Apple.  Except as
  26.                 expressly stated in this notice, no other rights or licenses, express or implied,
  27.                 are granted by Apple herein, including but not limited to any patent rights that
  28.                 may be infringed by your derivative works or by other works in which the Apple
  29.                 Software may be incorporated.
  30.  
  31.                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
  32.                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  33.                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  35.                 COMBINATION WITH YOUR PRODUCTS.
  36.  
  37.                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  38.                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  39.                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  40.                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
  41.                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  42.                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  43.                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44.                 
  45.     Change History (most recent first):
  46.  
  47.                 2000/10/02        Created        SC
  48.  
  49. */
  50.  
  51. #define TARGET_API_MAC_CARBON 1
  52.  
  53. #include <AppleEvents.h>
  54. #include <Events.h>
  55. #include <Gestalt.h>
  56. #include <Lists.h>
  57. #include <Menus.h>
  58. #include <Quickdraw.h>
  59. #include <ToolUtils.h>
  60. #include <Types.h>
  61. #include <Windows.h>
  62.  
  63. //    Constants
  64.  
  65. #define    kALRT_About                200        // About... alert
  66.  
  67. #define    kMBAR_Main                128        // Menu Bar
  68.  
  69. #define    kMENU_Apple                128        // Apple menu
  70. #define    kMENU_File                129        // File menu 
  71. #define    kMENU_Edit                130        // Edit menu 
  72.  
  73. #define kAboutMenuItem            1
  74. #define kNewMenuItem            1
  75. #define kCloseMenuItem            2
  76. #define kQuitSeparatorMenuItem    3
  77. #define kQuitMenuItem            4
  78.  
  79. #define kDefaultHorizontalCells 4
  80. #define kDefaultVerticalCells    10
  81.  
  82. #define kCellWidth                60
  83. #define kCellHeight             16
  84.  
  85. //    Global variables
  86.  
  87. Boolean gQuit;
  88.  
  89. //    Local functions
  90.  
  91. OSErr MyCreateMenus( void );
  92. OSErr MyCreateWindow( void );
  93.  
  94. //    Classic event handler functions
  95.  
  96. void MyHandleEvent( void );
  97. void MyActivateWindow( EventRecord *event, WindowRef window );
  98. void MyClickWindow( EventRecord *event, WindowRef window );
  99. void MyCloseWindow( WindowRef window );
  100. void MyDrawWindow( WindowRef window );
  101. void MyMenuHandler( long menuResult );
  102. void MyResizeList( WindowRef window );
  103.  
  104. //    Apple event handler functions
  105.  
  106. static pascal OSErr MyQuitAppleEventHandler( const AppleEvent *event, AppleEvent *reply,
  107.                                              UInt32 refCon );
  108.                                              
  109. //    The custom list definition function
  110.                                              
  111. static pascal void MyListDefinition( short message, Boolean select, Rect *rect, Cell cell,
  112.                                      short lDataOffset, short lDataLen, ListHandle lHandle );
  113.  
  114. // --------------------------------------------------------------------------------
  115. //
  116. //    main
  117. //
  118. //    Main entry point.
  119. //
  120.  
  121. void main( void )
  122. {
  123.     OSErr error;
  124.     
  125.     //    Initialize our global variables.
  126.     
  127.     gQuit = false;
  128.     
  129.     InitCursor();
  130.     
  131.     //    Install an Apple event handler for Quit Apple events. Under Mac OS X, when the user
  132.     //    chooses the Quit command from the application menu, we receive a quit Apple event and
  133.     //    this is how we handle it.
  134.     
  135.     error = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication,
  136.                                    NewAEEventHandlerUPP( MyQuitAppleEventHandler ), 0, false );                //    This is not a system handler.
  137.  
  138.     //    Load and initialize the menu bar.
  139.  
  140.     if( error == noErr )
  141.         error = MyCreateMenus();
  142.  
  143.     //    Create a new window, including our custom list.
  144.  
  145.     if( error == noErr )
  146.         error = MyCreateWindow();
  147.  
  148.     //    Handle events until it's time to quit.
  149.     
  150.     if( error == noErr ) {
  151.         while( gQuit == false )
  152.             MyHandleEvent();
  153.     }
  154.     
  155.     //    Terminate.
  156.     
  157.     ExitToShell();
  158. }
  159.  
  160. // --------------------------------------------------------------------------------
  161. //
  162. //    MyCreateMenus
  163. //
  164. //    Load our menu bar and initialize it.
  165. //
  166.  
  167. OSErr MyCreateMenus( void )
  168. {
  169.     OSErr        error;
  170.     Handle        menuBar;
  171.     long        response;
  172.     MenuRef        menuRef;
  173.     
  174.     error = noErr;
  175.     
  176.     //    Load the menu bar from the 'MBAR' resource.
  177.     
  178.     menuBar = GetNewMBar( kMBAR_Main );
  179.     if( menuBar ) {
  180.  
  181.         //    Set the loaded menu bar as the current menu bar and draw it.
  182.     
  183.         SetMenuBar( menuBar );
  184.         DrawMenuBar();
  185.         
  186.         //    If the menu bar uses the Aqua layout, delete the Quit menu item from the File menu
  187.         //    because under Aqua, a Quit menu item is automatically added to the application
  188.         //    menu.
  189.         
  190.         if( Gestalt( gestaltMenuMgrAttr, &response ) == noErr &&
  191.             ( response & gestaltMenuMgrAquaLayoutMask ) ) {
  192.             menuRef = GetMenuHandle( kMENU_File );
  193.             DeleteMenuItem( menuRef, kQuitMenuItem );
  194.             DeleteMenuItem( menuRef, kQuitSeparatorMenuItem );
  195.         }
  196.     }
  197.     else
  198.         error = resNotFound;
  199.     return error;
  200. }
  201.  
  202. // --------------------------------------------------------------------------------
  203. //
  204. //    MyCreateWindow
  205. //
  206. //    .
  207. //
  208.  
  209. OSErr MyCreateWindow( void )
  210. {
  211.     OSErr error;
  212.     ListHandle listHandle;
  213.     Point size;
  214.     Rect dataBounds;
  215.     Rect viewRect;
  216.     Rect windowRect;
  217.     ListDefSpec listDefSpec;
  218.     WindowRef windowRef;
  219.     
  220.     listHandle = NULL;
  221.  
  222.     //    Create a standard document window, position it appropriately on the screen, and set its
  223.     //    title. The window is hidden by default, so when we're done with all our initialization,
  224.     //    we need to call ShowWindow.
  225.     
  226.     SetRect( &windowRect, 0, 0, kCellWidth * kDefaultHorizontalCells + 15,
  227.              kCellHeight * kDefaultVerticalCells + 15 );
  228.     
  229.     error = CreateNewWindow( kDocumentWindowClass,                //    Standard document window.
  230.                              kWindowStandardDocumentAttributes,    //    Standard attributes for a
  231.                                                                  //    document window.
  232.                              &windowRect,                        //    The initial window bounds.
  233.                              &windowRef );                        //    If the call is successful, a
  234.                                                                  //    reference to the window is
  235.                                                                  //    returned.
  236.  
  237.     //    Resposition this window on the screen to a sensible location.
  238.  
  239.     if( error == noErr )
  240.         error = RepositionWindow( windowRef, NULL, kWindowCascadeOnMainScreen );
  241.  
  242.     //    Set the window title to "Carbon Custom List Sample."
  243.  
  244.     if( error == noErr ) {
  245.         SetWTitle( windowRef, "\pCarbon Custom List Sample" );
  246.         SetPortWindowPort( windowRef );
  247.     }
  248.     
  249.     //    Create a custom definition list. We use CreateCustomList instead of LNew. The ListDefSpec
  250.     //    data structure contains the list definition type (in this case it's a callback function so
  251.     //    we use kListDefUserProcType) and the actual callback UPP. MyListDefinition will be called
  252.     //    to draw items in the list.
  253.  
  254.     if( error == noErr ) {
  255.         SetRect( &viewRect, 0, 0, kCellWidth * kDefaultHorizontalCells,
  256.                  kCellHeight * kDefaultVerticalCells );
  257.         SetRect( &dataBounds, 0, 0, 100, 100 );
  258.         SetPt( &size, kCellWidth, kCellHeight );
  259.         
  260.         //    Define our list definition structure. We specify kListDefUserProcType for the
  261.         //    definition type and pass our list definition procedure using NewListDefUPP.
  262.     
  263.         listDefSpec.defType = kListDefUserProcType;
  264.         listDefSpec.u.userProc = NewListDefUPP( MyListDefinition );
  265.  
  266.         error = CreateCustomList( &viewRect,
  267.                                   &dataBounds,        //    The initial number of cells in the list.
  268.                                   size,                //    The size of each cell.
  269.                                   &listDefSpec,        //    The ListDefSpec that we created earlier.
  270.                                   windowRef,        //    The window in which the list will be
  271.                                                       //    created.
  272.                                   true,                //    Draw it.
  273.                                   true,                //    Our list has a grow box.
  274.                                   true,                //    Our list has a horizontal scroll bar.
  275.                                   true,                //    Our list has a vertical scroll bar.
  276.                                   &listHandle );    //    If the call is successful, a reference
  277.                                                       //    to the list is returned.
  278.     }
  279.     
  280.     //    Store a handle to the list in the window refCon.
  281.     
  282.     if( error == noErr )
  283.         SetWRefCon( windowRef, (long) listHandle );
  284.  
  285.     //    If an error occured, dispose of the window and the list if they were created.
  286.  
  287.     if( error ) {
  288.         if( windowRef )
  289.             DisposeWindow( windowRef );
  290.         if( listHandle )
  291.             LDispose( listHandle );
  292.     }
  293.  
  294.     //    CreateNewWindow creates windows that are not visible by default, so if no error occured,
  295.     //    call ShowWindow to make it visible.
  296.  
  297.     if( error == noErr )
  298.         ShowWindow( windowRef );
  299.     return error;
  300. }
  301.  
  302. #pragma mark -
  303.  
  304. // --------------------------------------------------------------------------------
  305. //
  306. //    MyHandleEvent
  307. //
  308. //    Our event loop. Called repeatedly to retrieve and handle events until it's
  309. //    time to quit.
  310. //
  311.  
  312. void MyHandleEvent( void )
  313. {
  314.     EventRecord event;
  315.     short            part;
  316.     long            size;
  317.     Boolean            hit;
  318.     Rect            tempRect;
  319.     WindowPtr        myWindow;
  320.     
  321.     if( WaitNextEvent( everyEvent, &event, 0xFFFFFFFF, nil ) ) {
  322.         switch( event.what ) {
  323.             case mouseDown:
  324.                 part = FindWindow( event.where, &myWindow );
  325.                 switch( part ) {
  326.                     case inMenuBar:              // process a moused menu command
  327.                         MyMenuHandler( MenuSelect( event.where ) );
  328.                         break;
  329.                     case inSysWindow:            // let system handle it
  330.                         //SystemClick( event, myWindow );
  331.                         break;
  332.                     case inContent:
  333.                         MyClickWindow( &event, myWindow );
  334.                         break;
  335.                     case inDrag:                
  336.                         GetRegionBounds( GetGrayRgn(), &tempRect );
  337.                         DragWindow( myWindow, event.where, &tempRect );
  338.                         break;
  339.                     case inGrow:
  340.                         size = GrowWindow( myWindow,
  341.                                            event.where,
  342.                                            NULL );    //    Bounds can only be NULL w/Carbon 1.0 or later
  343.                         if( size ) {
  344.                             SizeWindow( myWindow, LoWord( size ), HiWord( size ), true );
  345.                             MyResizeList( myWindow );
  346.                             GetPortBounds( GetWindowPort( myWindow ), &tempRect );
  347.                             InvalWindowRect( myWindow, &tempRect );
  348.                         }
  349.                         break;
  350.                     case inGoAway:
  351.                         if( TrackGoAway( myWindow, event.where ) )
  352.                             MyCloseWindow( myWindow );
  353.                         break;
  354.                     case inZoomIn:
  355.                     case inZoomOut:
  356.                         hit = TrackBox( myWindow, event.where, part );
  357.                         if( hit ) {
  358.                             SetPort( GetWindowPort( myWindow ) );   // window must be current port
  359.                             EraseRect( GetWindowPortBounds( myWindow, &tempRect ) );    // inval/erase because of ZoomWindow bug
  360.                             ZoomWindow( myWindow, part, true );
  361.                             InvalWindowRect( myWindow, GetWindowPortBounds( myWindow, &tempRect ) );
  362.                             MyResizeList( myWindow );
  363.                         }
  364.                         break;
  365.                 }
  366.                 break;
  367.             case keyDown:
  368.             case autoKey:
  369.                 if( event.modifiers & cmdKey ) {
  370.                     if( event.what == keyDown )
  371.                         MyMenuHandler( MenuKey( event.message & charCodeMask ) );
  372.                 }
  373.                 break;
  374.             case activateEvt:
  375.                 MyActivateWindow( &event, (WindowRef) event.message );
  376.                 break;
  377.             case updateEvt:
  378.                 MyDrawWindow( (WindowRef) event.message );
  379.                 break;
  380.             case kHighLevelEvent:
  381.                 AEProcessAppleEvent( &event );
  382.                 break;
  383.             case diskEvt:
  384.                 break;
  385.         }
  386.     }
  387. }
  388.  
  389. // --------------------------------------------------------------------------------
  390. //
  391. //    MyActivateWindow
  392. //
  393. //    Handles window activation/deactivation events by activating/deactivating the
  394. //    list appropriately.
  395. //
  396.  
  397. void MyActivateWindow( EventRecord *event, WindowRef window )
  398. {
  399.     ListHandle    listHandle;
  400.  
  401.     if( window ) {
  402.         listHandle = (ListHandle) GetWRefCon( window );
  403.         if( listHandle ) {
  404.             if( event->modifiers & activeFlag )
  405.                 LActivate( true, listHandle );
  406.             else
  407.                 LActivate( false, listHandle );
  408.         }
  409.     }
  410. }
  411.  
  412. // --------------------------------------------------------------------------------
  413. //
  414. //    MyClickWindow
  415. //
  416. //    Handle a mouse-down event in the window.
  417. //
  418.  
  419. void MyClickWindow( EventRecord *event, WindowRef window )
  420. {
  421.     ListHandle    listHandle;
  422.     Point        localPoint;
  423.     Rect        viewBounds;
  424.  
  425.     if( window ) {
  426.         listHandle = (ListHandle) GetWRefCon( window );
  427.         if( listHandle ) {
  428.  
  429.             //    If the clicked window is not frontmost , call SelectWindow to bring it to
  430.             //    the front.
  431.  
  432.             if( window != FrontWindow() )
  433.                 SelectWindow( window );
  434.                 
  435.             //    We are given the location of the mouse click in global coordinates. The List
  436.             //    Manager expects local coordinates, so we first convert to local coordinates.
  437.  
  438.             SetPortWindowPort( window );
  439.             localPoint = event->where;
  440.             GlobalToLocal( &localPoint );
  441.  
  442.             //    Get the list's view bounds. Then, if the click was within the view bounds,
  443.             //    call LClick to handle the click.
  444.  
  445.             GetListViewBounds( listHandle, &viewBounds );
  446.             viewBounds.right += 15;
  447.             viewBounds.bottom += 15;
  448.             if( PtInRect( localPoint, &viewBounds ) ) {
  449.                 if( LClick( localPoint, event->modifiers, listHandle ) ) {
  450.  
  451.                     //    If LClick returns true, the user double-clicked in the list. Handle
  452.                     //    double-clicks here.
  453.  
  454.  
  455.                 }
  456.             }
  457.         }
  458.     }
  459. }
  460.  
  461. // --------------------------------------------------------------------------------
  462. //
  463. //    MyCloseWindow
  464. //
  465. //    Disposes of a window and its associated list.
  466. //
  467.  
  468. void MyCloseWindow( WindowRef window )
  469. {
  470.     ListHandle    listHandle;
  471.     
  472.     if( window ) {
  473.         listHandle = (ListHandle) GetWRefCon( window );
  474.         if( listHandle )
  475.             LDispose( listHandle );
  476.         DisposeWindow( window );
  477.     }
  478. }
  479.  
  480. // --------------------------------------------------------------------------------
  481. //
  482. //    MyDrawWindow
  483. //
  484. //    Draws the contents (controls, grow icon, and list) of the window.
  485. //
  486.  
  487. void MyDrawWindow( WindowRef window )
  488. {
  489.     GrafPtr        curPort;
  490.     ListHandle    listHandle;
  491.     Rect        tempRect;
  492.     RgnHandle    visRgn;
  493.     
  494.     if( window ) {
  495.         listHandle = (ListHandle) GetWRefCon( window );
  496.         if( listHandle ) {
  497.             GetWindowPortBounds( window, &tempRect );
  498.             GetPortVisibleRegion( GetWindowPort( window ), visRgn = NewRgn() );
  499.             GetPort( &curPort );
  500.             SetPort( GetWindowPort( window ) );
  501.             BeginUpdate( window );
  502.             EraseRect( &tempRect );
  503.             GetListViewBounds( listHandle, &tempRect );
  504.             LUpdate( visRgn, listHandle );
  505.             DrawControls( window );
  506.             DrawGrowIcon( window );
  507.             EndUpdate( window );
  508.             SetPort( curPort );
  509.             DisposeRgn( visRgn );
  510.         }
  511.     }
  512. }
  513.  
  514. // --------------------------------------------------------------------------------
  515. //
  516. //    MyMenuHandler
  517. //
  518. //    Handles a mouse-based or keyboard-based menu selection.
  519. //
  520.  
  521. void MyMenuHandler( long menuResult )
  522. {
  523.     short menuID;            // resource ID of selected menu
  524.     short menuItem;            // item number of selected menu
  525.     
  526.     menuID = HiWord( menuResult );
  527.     menuItem = LoWord( menuResult );
  528.     
  529.     switch( menuID ) {
  530.         case kMENU_Apple:
  531.             switch( menuItem ) {
  532.                 case kAboutMenuItem:
  533.                     Alert( kALRT_About, nil );  // simple alert dialog box
  534.                     break;
  535.                 default:
  536.                     break;
  537.             }
  538.             break;
  539.         case kMENU_File:
  540.             switch( menuItem ) {
  541.                 case kNewMenuItem:
  542.                     MyCreateWindow();
  543.                     break;
  544.                 case kCloseMenuItem:
  545.                     MyCloseWindow( FrontWindow() );
  546.                     break;
  547.                 case kQuitMenuItem:
  548.                     gQuit = true;
  549.                     break;
  550.             }
  551.             break;
  552.         case kMENU_Edit:
  553.             break;
  554.     }
  555.     HiliteMenu( 0 );
  556. }
  557.  
  558. // --------------------------------------------------------------------------------
  559. //
  560. //    MyResizeList
  561. //
  562. //    Called when a window is zoomed or resized. Resizes the list to match.
  563. //
  564.  
  565. void MyResizeList( WindowRef window )
  566. {
  567.     ListHandle    listHandle;
  568.     Rect        viewRect;
  569.     
  570.     if( window ) {
  571.         listHandle =( ListHandle ) GetWRefCon( window );
  572.         if( listHandle ) {
  573.             GetPortBounds( GetWindowPort( window ), &viewRect );
  574.             LSize( viewRect.right - 15, viewRect.bottom - 15, listHandle );
  575.         }
  576.     }
  577. }
  578.  
  579. #pragma mark -
  580.  
  581. // --------------------------------------------------------------------------------
  582. //
  583. //    MyQuitAppleEventHandler
  584. //
  585. //    Called in response to a Quit Apple event. Set gQuit to true so the application
  586. //    will terminate next time through the event loop.
  587. //
  588.  
  589. static pascal OSErr MyQuitAppleEventHandler( const AppleEvent *event, AppleEvent *reply,
  590.                                              UInt32 refCon )
  591. {
  592.     gQuit = true;
  593.     return noErr;
  594. }
  595.  
  596. #pragma mark -
  597.  
  598. // --------------------------------------------------------------------------------
  599. //
  600. //    MyListDefinition
  601. //
  602. //    This is the actual custom list definition function. It is called for each cell
  603. //    when the cell needs to be drawn or the cell's hilite status changes. This
  604. //    function is registered with the List Manager in CreateCustomList.
  605. //
  606.  
  607. static pascal void MyListDefinition( short message, Boolean isSelected, Rect *drawRect,
  608.                                      Cell cell, short dataOffset, short dataLength,
  609.                                      ListHandle listHandle )
  610. {
  611.     FontInfo fontInfo;
  612.     GrafPtr grafPtr;
  613.     RgnHandle savedClipRegion;
  614.     SInt32 savedPenMode;
  615.     unsigned char x [26], y [12];
  616.     
  617.     //    Calculate the cell rect.
  618.     
  619.     switch( message ) {
  620.         case lDrawMsg:
  621.         
  622.             //    Save the current clip region, and set the clip region to the area we are about
  623.             //    to draw.
  624.             
  625.             savedClipRegion = NewRgn();
  626.             GetClip( savedClipRegion );
  627.             ClipRect( drawRect );
  628.             EraseRect( drawRect );
  629.             
  630.             //    Draw the cell contents. For this example we just draw the coordinate numbers
  631.             //    for each cell, but you will probably extract the cell data( dataOffset and
  632.             //    dataLength ) to draw the contents of your cell.
  633.             
  634.             GetFontInfo( &fontInfo );
  635.             
  636.             NumToString( cell.h, x );
  637.             NumToString( cell.v, y );
  638.             x [0]++;
  639.             x [x [0]] = ',';
  640.             x [0]++;
  641.             x [x [0]] = ' ';
  642.             BlockMoveData( y + 1, x + x [0] + 1, y [0] );
  643.             x [0] += y [0];
  644.             MoveTo( drawRect->left +( kCellWidth - StringWidth( x ) ) / 2,
  645.                     drawRect->top + fontInfo.ascent +
  646.                     ( kCellHeight - fontInfo.ascent - fontInfo.descent ) / 2 );
  647.             DrawString( x );
  648.             
  649.             //    If the cell is hilited, do the hilite now. Paint the cell contents with the
  650.             //    appropriate QuickDraw transform mode.
  651.             
  652.             if( isSelected ) {
  653.                 GetPort( &grafPtr );
  654.                 savedPenMode = GetPortPenMode( grafPtr );
  655.                 SetPortPenMode( grafPtr, hilitetransfermode );
  656.                 PaintRect( drawRect );
  657.                 SetPortPenMode( grafPtr, savedPenMode );
  658.             }
  659.             
  660.             //    Restore the saved clip region.
  661.             
  662.             SetClip( savedClipRegion );
  663.             DisposeRgn( savedClipRegion );
  664.             break;
  665.         case lHiliteMsg:
  666.             
  667.             //    Hilite or unhilite the cell. Paint the cell contents with the
  668.             //    appropriate QuickDraw transform mode.
  669.             
  670.             GetPort( &grafPtr );
  671.             savedPenMode = GetPortPenMode( grafPtr );
  672.             SetPortPenMode( grafPtr, hilitetransfermode );
  673.             PaintRect( drawRect );
  674.             SetPortPenMode( grafPtr, savedPenMode );
  675.             break;
  676.     }
  677. }